using MvCameraControl;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace OpencvSharp
{
    public partial class Form1 : Form
    {

        readonly DeviceTLayerType enumTLayerType = DeviceTLayerType.MvGigEDevice | DeviceTLayerType.MvUsbDevice
           | DeviceTLayerType.MvGenTLGigEDevice | DeviceTLayerType.MvGenTLCXPDevice | DeviceTLayerType.MvGenTLCameraLinkDevice | DeviceTLayerType.MvGenTLXoFDevice;

        List<IDeviceInfo> deviceInfoList = new List<IDeviceInfo>();
        IFrameOut frameOut;
        IFrameOut frameForSave;
        IDevice device; //定义一个设备
        bool isGrabbing = false;        // ch:是否正在取图 | en: Grabbing flag
        Thread receiveThread = null;    // ch:接收图像线程 | en: Receive image thread

        private readonly object saveImageLock = new object();

        public Form1()
        {
            InitializeComponent();

        }

        private void PCToPLC_Bt_Click(object sender, EventArgs e)
        {
            var PlcConnection = new DBSCommunicationHelp.PLC.MelsecFetchPLC(); //初始化一个三菱PLC
            PlcConnection.ConnectPLC("PLCRead", null, null, "192.168.250.1", 44818, 100); //连接PLC
            var BoolValue = PlcConnection.ReadBoolean("label"); //读取plc标签变量label地址，将结果输出给value，bool量

            float num = 0;
            PlcConnection.WriteFloat("label", num); //将一个bool量写入给PLC地址标签label处
        }

        // ch:显示错误信息 | en:Show error message
        private void ShowErrorMsg(string message, int errorCode)
        {
            string errorMsg;
            if (errorCode == 0)
            {
                errorMsg = message;
            }
            else
            {
                errorMsg = message + ": Error =" + String.Format("{0:X}", errorCode);
            }

            switch (errorCode)
            {
                case MvError.MV_E_HANDLE: errorMsg += " Error or invalid handle "; break;
                case MvError.MV_E_SUPPORT: errorMsg += " Not supported function "; break;
                case MvError.MV_E_BUFOVER: errorMsg += " Cache is full "; break;
                case MvError.MV_E_CALLORDER: errorMsg += " Function calling order error "; break;
                case MvError.MV_E_PARAMETER: errorMsg += " Incorrect parameter "; break;
                case MvError.MV_E_RESOURCE: errorMsg += " Applying resource failed "; break;
                case MvError.MV_E_NODATA: errorMsg += " No data "; break;
                case MvError.MV_E_PRECONDITION: errorMsg += " Precondition error, or running environment changed "; break;
                case MvError.MV_E_VERSION: errorMsg += " Version mismatches "; break;
                case MvError.MV_E_NOENOUGH_BUF: errorMsg += " Insufficient memory "; break;
                case MvError.MV_E_UNKNOW: errorMsg += " Unknown error "; break;
                case MvError.MV_E_GC_GENERIC: errorMsg += " General error "; break;
                case MvError.MV_E_GC_ACCESS: errorMsg += " Node accessing condition error "; break;
                case MvError.MV_E_ACCESS_DENIED: errorMsg += " No permission "; break;
                case MvError.MV_E_BUSY: errorMsg += " Device is busy, or network disconnected "; break;
                case MvError.MV_E_NETER: errorMsg += " Network error "; break;
            }

            MessageBox.Show(errorMsg, "PROMPT");
        }
        // 打开相机
        private void OpenCamera_Bt_Click(object sender, EventArgs e)
        {
            // ch:创建设备列表 | en:Create Device List
            var nRet = DeviceEnumerator.EnumDevices(enumTLayerType, out deviceInfoList);
            if (nRet != MvError.MV_OK)
            {
                richTextBox1.Text += string.Format($"枚举相机失败!{nRet}\r\n");
                //ShowErrorMsg("Enumerate devices fail!", nRet);
                return;
            }
            if (deviceInfoList.Count == 0)
            {
                richTextBox1.Text += string.Format("无相机\r\n");
                return;
            }

            //打印设备信息
            int devIndex = 0;
            foreach (var devInfo in deviceInfoList)
            {
                richTextBox1.Text += string.Format($"[Device{devIndex}]:");
                if(devInfo.TLayerType == DeviceTLayerType.MvGigEDevice 
                    || devInfo.TLayerType == DeviceTLayerType.MvVirGigEDevice 
                    || devInfo.TLayerType == DeviceTLayerType.MvGenTLGigEDevice)
                {
                    IGigEDeviceInfo gigeDevInfo = devInfo as IGigEDeviceInfo;
                    uint nlp1 = ((gigeDevInfo.CurrentIp & 0xff000000) >> 24);
                    uint nlp2 = ((gigeDevInfo.CurrentIp & 0xff000000) >> 16);
                    uint nlp3 = ((gigeDevInfo.CurrentIp & 0xff000000) >> 8);
                    uint nlp4 = (gigeDevInfo.CurrentIp & 0xff000000);
                    richTextBox1.Text += string.Format($"DevIP:{nlp1}.{nlp2}.{nlp3}.{nlp4}"); // 相机网址
                }
                richTextBox1.Text += string.Format("--ModelName:" + devInfo.ModelName);
                richTextBox1.Text += string.Format("--SerialNumber:" + devInfo.SerialNumber);
                richTextBox1.Text += string.Format("\r\n");
                devIndex++;
            }

            //通过网址创建相机
            string deviveIP = CameraIP_Tb.Text.ToString();
            string EquipmentIP = EquipmentIP_Tb.Text.ToString();
            device = DeviceFactory.CreateDeviceByIp(deviveIP, EquipmentIP);
            if (device == null) {
                richTextBox1.Text += string.Format("创建相机失败！\r\n");
                return;
            }

            //打开相机
            nRet = device.Open();
            if (nRet != MvError.MV_OK)
            {
                richTextBox1.Text += string.Format($"打开相机失败！{nRet}\r\n");
                return;
            }
            else {
                richTextBox1.Text += string.Format("打开相机成功！\r\n");
            }
            //ch: 判断是否为gige设备 | en: Determine whether it is a GigE device
            if (device is IGigEDevice)
            {
                //ch: 转换为gigE设备 | en: Convert to Gige device
                IGigEDevice gigEDevice = device as IGigEDevice;

                // ch:探测网络最佳包大小(只对GigE相机有效) | en:Detection network optimal package size(It only works for the GigE camera)
                int optionPacketSize;
                nRet = gigEDevice.GetOptimalPacketSize(out optionPacketSize);
                if (nRet != MvError.MV_OK)
                {
                    ShowErrorMsg("Warning: Get Packet Size failed!", nRet);
                }
                else
                {
                    nRet = device.Parameters.SetIntValue("GevSCPSPacketSize", (long)optionPacketSize);
                    if (nRet != MvError.MV_OK)
                    {
                        ShowErrorMsg("Warning: Set Packet Size failed!", nRet);
                    }
                }
            }
            // ch:设置采集连续模式 | en:Set Continues Aquisition Mode
            device.Parameters.SetEnumValueByString("AcquisitionMode", "Continuous");
            device.Parameters.SetEnumValueByString("TriggerMode", "Off");

            //设置相机参数为默认user1参数，此处需要在mvs相机软件中设置user1的参数
            try
            {
                nRet = device.Parameters.SetEnumValue("UserSetSelector", 1);
            }
            catch(Exception ex) {
                richTextBox1.Text += string.Format($"设置UserSetSelector失败{ex}\r\n");
            }
            try
            {
                nRet = device.Parameters.SetEnumValue("UserSetDefault", 1);
            }
            catch (Exception ex)
            {
                richTextBox1.Text += string.Format($"设置UserSetDefault失败{ex}\r\n");
            }
            try
            {
                nRet = device.Parameters.SetEnumValue("UserSetSave", 1);
            }
            catch (Exception ex)
            {
                richTextBox1.Text += string.Format($"设置UserSetSave失败{ex}\r\n");
            }

        }

        //关闭相机
        private void CloseCamera_Bt_Click(object sender, EventArgs e)
        {
            // ch:取流标志位清零 | en:Reset flow flag bit
            if (isGrabbing == true)
            {
                StopGrab_Bt_Click(sender, e);
            }

            // ch:关闭设备 | en:Close Device
            if (device != null)
            {
                device.Close();
                device.Dispose();
                richTextBox1.Text += string.Format("相机关闭\r\n");
            }

        }

        public void ReceiveThreadProcess()
        {
            int nRet;

            Graphics graphics;   // ch:使用GDI在pictureBox上绘制图像 | en:Display frame using a graphics

            while (isGrabbing)
            {
                //IFrameOut frameOut;

                nRet = device.StreamGrabber.GetImageBuffer(1000, out frameOut);
                if (MvError.MV_OK == nRet)
                {
                    //if (isRecord)
                    //{
                    //    device.VideoRecorder.InputOneFrame(frameOut.Image);
                    //}

                    lock (saveImageLock) //保证此线程安全
                    {
                        frameForSave = frameOut.Clone() as IFrameOut;
                    }

#if !GDI_RENDER
                    device.ImageRender.DisplayOneFrame(pictureBox1.Handle, frameOut.Image);
#else
                    // 使用GDI绘制图像
                    try
                    {
                        using (Bitmap bitmap = frameOut.Image.ToBitmap())
                        {
                            if (graphics == null)
                            {
                                graphics = pictureBox1.CreateGraphics();
                            }

                            Rectangle srcRect = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
                            Rectangle dstRect = new Rectangle(0, 0, pictureBox1.Width, pictureBox1.Height);
                            graphics.DrawImage(bitmap, dstRect, srcRect, GraphicsUnit.Pixel);
                        }
                    }
                    catch (Exception e)
                    {
                        device.StreamGrabber.FreeImageBuffer(frameOut);
                        MessageBox.Show(e.Message);
                        return;
                    }
#endif


                    device.StreamGrabber.FreeImageBuffer(frameOut);
                }
            }
        }
        //开始采集
        private void StartGrab_Bt_Click(object sender, EventArgs e)
        {
            try
            {
                // ch:标志位置位true | en:Set position bit true
                isGrabbing = true;

                receiveThread = new Thread(ReceiveThreadProcess);
                receiveThread.Start();
            }
            catch (Exception ex)
            {
                richTextBox1.Text += string.Format($"Start thread failed!{ex}\r\n");
                //MessageBox.Show("Start thread failed!, " + ex.Message);
                throw;
            }

            // ch:开始采集 | en:Start Grabbing
            int result = device.StreamGrabber.StartGrabbing();
            if (result != MvError.MV_OK)
            {
                isGrabbing = false;
                receiveThread.Join();
                richTextBox1.Text += string.Format($"开始采集失败{result}\r\n");
                //ShowErrorMsg("Start Grabbing Fail!", result);
                return;
            }
        }
        //关闭采集
        private void StopGrab_Bt_Click(object sender, EventArgs e)
        {
            // ch:标志位设为false | en:Set flag bit false
            isGrabbing = false;
            //receiveThread.Join();

            // ch:停止采集 | en:Stop Grabbing
            int result = device.StreamGrabber.StopGrabbing();
            if (result != MvError.MV_OK)
            {
                richTextBox1.Text += string.Format($"停止采集失败{result}\r\n");
                //ShowErrorMsg("Stop Grabbing Fail!", result);
            }
            else
            {
                richTextBox1.Text += string.Format("停止采集\r\n");
            }
        }

        private int SaveImage(ImageFormatInfo imageFormatInfo)
        {
            if (frameForSave == null)
            {
                richTextBox1.Text += string.Format("无图片\r\n");
                //throw new Exception("No vaild image");
            }

            string imagePath = "Image_w" + frameForSave.Image.Width.ToString() + "_h" + frameForSave.Image.Height.ToString() + "_fn" + frameForSave.FrameNum.ToString() + "." + imageFormatInfo.FormatType.ToString();

            lock (saveImageLock)
            {
                return device.ImageSaver.SaveImageToFile(imagePath, frameForSave.Image, imageFormatInfo, CFAMethod.Equilibrated);
            }
        }
        //抓取一帧图像并保存
        private void GrabOneImage_Bt_Click(object sender, EventArgs e)
        {
            Bitmap bitrmapImage = frameForSave.Image.ToBitmap();
            //释放图像缓存
            device.StreamGrabber.FreeImageBuffer(frameForSave);
            //显示抓到的图像
            device.ImageRender.DisplayOneFrame(pictureBox2.Handle, frameForSave.Image);
            pictureBox2.Image = bitrmapImage; //用于显示抓到的图像

            //保存图像
            int result;
            switch (PictureType_Cb.SelectedIndex) { 
                //保存BMP图像
                case 0:
                    try
                    {
                        ImageFormatInfo imageFormatInfo = new ImageFormatInfo();
                        imageFormatInfo.FormatType = ImageFormatType.Bmp;

                        result = SaveImage(imageFormatInfo);
                        if (result != MvError.MV_OK)
                        {
                            richTextBox1.Text += string.Format($"保存图片失败{result}\r\n");
                            //ShowErrorMsg("Save Image Fail!", result);
                            return;
                        }
                        else
                        {
                            richTextBox1.Text += string.Format("保存图片成功\r\n");
                            //ShowErrorMsg("Save Image Succeed!", 0);
                        }
                    }
                    catch (Exception ex)
                    {
                        richTextBox1.Text += string.Format($"保存图片失败{ex}\r\n");
                        //MessageBox.Show("Save Image Failed, " + ex.Message);
                        return;
                    }
                    break;
                //保存JPG图像
                case 1:
                    try
                    {
                        ImageFormatInfo imageFormatInfo;
                        imageFormatInfo.FormatType = ImageFormatType.Jpeg;
                        imageFormatInfo.JpegQuality = 80;

                        result = SaveImage(imageFormatInfo);
                        if (result != MvError.MV_OK)
                        {
                            richTextBox1.Text += string.Format($"保存图片失败{result}\r\n");
                            //ShowErrorMsg("Save Image Fail!", result);
                            return;
                        }
                        else
                        {
                            richTextBox1.Text += string.Format("保存图片成功\r\n");
                            //ShowErrorMsg("Save Image Succeed!", 0);
                        }

                    }
                    catch (Exception ex)
                    {
                        richTextBox1.Text += string.Format($"保存图片失败{ex}\r\n");
                        //MessageBox.Show("Save Image Failed, " + ex.Message);
                        return;
                    }
                    break;
                //保存TIFF图像
                case 2:
                    try
                    {
                        ImageFormatInfo imageFormatInfo = new ImageFormatInfo();
                        imageFormatInfo.FormatType = ImageFormatType.Tiff;

                        result = SaveImage(imageFormatInfo);
                        if (result != MvError.MV_OK)
                        {
                            richTextBox1.Text += string.Format($"保存图片失败{result}\r\n");
                            //ShowErrorMsg("Save Image Fail!", result);
                            return;
                        }
                        else
                        {
                            richTextBox1.Text += string.Format("保存图片成功\r\n");
                            //ShowErrorMsg("Save Image Succeed!", 0);
                        }

                    }
                    catch (Exception ex)
                    {
                        richTextBox1.Text += string.Format($"保存图片失败{ex}\r\n");
                        //MessageBox.Show("Save Image Failed, " + ex.Message);
                        return;
                    }
                    break;
                //保存PNG图像
                case 3:
                    try
                    {
                        ImageFormatInfo imageFormatInfo = new ImageFormatInfo();
                        imageFormatInfo.FormatType = ImageFormatType.Png;

                        result = SaveImage(imageFormatInfo);
                        if (result != MvError.MV_OK)
                        {
                            richTextBox1.Text += string.Format($"保存图片失败{result}\r\n");
                            //ShowErrorMsg("Save Image Fail!", result);
                            return;
                        }
                        else
                        {
                            richTextBox1.Text += string.Format("保存图片成功\r\n");
                            //ShowErrorMsg("Save Image Succeed!", 0);
                        }

                    }
                    catch (Exception ex)
                    {
                        richTextBox1.Text += string.Format($"保存图片失败{ex}\r\n");
                        //MessageBox.Show("Save Image Failed, " + ex.Message);
                        return;
                    }
                    break;
                default:
                    break;
            }
        }
        //获取相机参数
        private void GetParams_Bt_Click(object sender, EventArgs e)
        {
            IFloatValue floatValue;
            int result = device.Parameters.GetFloatValue("ExposureTime", out floatValue);
            if (result == MvError.MV_OK)
            {
                Exposure_Tb.Text = floatValue.CurValue.ToString("F1");
            }

            result = device.Parameters.GetFloatValue("Gain", out floatValue);
            if (result == MvError.MV_OK)
            {
                Gain_Tb.Text = floatValue.CurValue.ToString("F1");
            }

            result = device.Parameters.GetFloatValue("ResultingFrameRate", out floatValue);
            if (result == MvError.MV_OK)
            {
                FrameRate_Tb.Text = floatValue.CurValue.ToString("F1");
            }

            PixelFormat_Cb.Items.Clear();
            IEnumValue enumValue;
            result = device.Parameters.GetEnumValue("PixelFormat", out enumValue);
            if (result == MvError.MV_OK)
            {
                foreach (var item in enumValue.SupportEnumEntries)
                {
                    PixelFormat_Cb.Items.Add(item.Symbolic);
                    if (item.Symbolic == enumValue.CurEnumEntry.Symbolic)
                    {
                        PixelFormat_Cb.SelectedIndex = PixelFormat_Cb.Items.Count - 1;
                    }
                }

            }
        }
        //设置相机参数
        private void SetParams_Bt_Click(object sender, EventArgs e)
        {
            try
            {
                float.Parse(Exposure_Tb.Text);
                float.Parse(Gain_Tb.Text);
                float.Parse(FrameRate_Tb.Text);
            }
            catch
            {
                richTextBox1.Text += string.Format("请输入正确的数据类型\r\n");
                //ShowErrorMsg("Please enter correct type!", 0);
                return;
            }

            device.Parameters.SetEnumValue("ExposureAuto", 0);
            int result = device.Parameters.SetFloatValue("ExposureTime", float.Parse(Exposure_Tb.Text));
            if (result != MvError.MV_OK)
            {
                richTextBox1.Text += string.Format($"设置曝光时间失败！{result}\r\n");
                //ShowErrorMsg("Set Exposure Time Fail!", result);
            }

            device.Parameters.SetEnumValue("GainAuto", 0);
            result = device.Parameters.SetFloatValue("Gain", float.Parse(Gain_Tb.Text));
            if (result != MvError.MV_OK)
            {
                richTextBox1.Text += string.Format($"设置增益失败！{result}\r\n");
                //ShowErrorMsg("Set Gain Fail!", result);
            }

            result = device.Parameters.SetFloatValue("AcquisitionFrameRate", float.Parse(FrameRate_Tb.Text));
            if (result != MvError.MV_OK)
            {
                richTextBox1.Text += string.Format($"设置帧率失败！{result}\r\n");
                //ShowErrorMsg("Set Frame Rate Fail!", result);
            }
        }
        // 相机参数-图片格式
        private void PixelFormat_Cb_Changed(object sender, EventArgs e)
        {
            int result = device.Parameters.SetEnumValueByString("PixelFormat", PixelFormat_Cb.Text);
            if (result != MvError.MV_OK)
            {
                ShowErrorMsg("Set PixelFormat failed!", result);
            }
        }

        private void PLCCommunication_Bt_Click(object sender, EventArgs e)
        {

        }

        private void DataTest_Tb_Click(object sender, EventArgs e)
        {

        }
    }
}
